package net.unix8.tool;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

import sun.misc.Cleaner;
public class Tools {
	public static void deleteDir(File dir){
		  if(dir.isDirectory()){
		   File[] files = dir.listFiles();
		   for(int i=0; i<files.length; i++) {
		    deleteDir(files[i]);
		   }
		  }
		  dir.delete();
		 }
	
	public static String formatTimeEight() throws Exception {
		Date d = new Date();		
		long rightTime = (long) (d.getTime() - 8 * 60 * 60 * 1000); //把当前得到的时间用date.getTime()的方法写成时间戳的形式，再加上8小时对应的毫秒数
		SimpleDateFormat sd=new SimpleDateFormat("yyyyMMddHHmmss");
		String newtime = sd.format(rightTime);//把得到的新的时间戳再次格式化成时间的格式
		return newtime;
		}
	public static void sleep(int t){
		try {
			//System.out.println("无主机休眠中");
			Thread.sleep(3000);
			//FileProcess.checkLeaveHostFile();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/*
	 * 二维字节数组追加合并
	 */
	public static byte[][]  ByteArrayAppend(byte[][] byte1, byte[][] byte2){//byte1 + byte2
		if(byte1 == null) return byte2;
		if(byte2 == null) return byte1;
		byte [][]data = new byte[3][];
		data[0] = Tools.addBytes(byte1[0],byte2[0]);
		data[1] = Tools.addBytes(byte1[1],byte2[1]);
		data[2] = Tools.addBytes(byte1[2],byte2[2]);
		return data;
	}

	/*
	 * 二维数组插入合并
	 */
	public static byte[][]  ByteArrayInsert(byte[][] byte2, byte[][] byte1){//byte2+byte1
		if(byte1 == null) return byte2;
		if(byte2 == null) return byte1;
		byte [][]data = new byte[3][];
		data[0] = Tools.addBytes(byte2[0],byte1[0]);
		data[1] = Tools.addBytes(byte2[1],byte1[1]);
		data[2] = Tools.addBytes(byte2[2],byte1[2]);
		return data;
	}
	/*
	 * 将二维bytes数组写入文件中
	 * start为开始写入的位置
	 * size为写入的二维数组每一行的大小，并不是整个二维数组的大小
	 */
	@SuppressWarnings("resource")
	public static void writeByteNToFile(String file, long start, long size, byte [][]data) throws IOException  {
		FileChannel fc = null;
		try {
			fc = new RandomAccessFile(file, "rw").getChannel();		
			MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, start, size * 3);//load or load
			out.put(data[0]);
			out.put(data[1]);
			out.put(data[2]);
			fc.close();
			try {
				clean(out);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw e; 
		}
	}
	/*
	 * 将一维bytes数组写入文件中
	 */
	@SuppressWarnings("resource")
	public static void writeByteNToFile(String file, long start, long size, byte []data) throws IOException  {
		FileChannel fc = null;
		try {
			fc = new RandomAccessFile(file, "rw").getChannel();		
			MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, start, size);//load or load
			out.put(data);
			fc.close();
			try {
				clean(out);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw e; 
		}
	}
	@SuppressWarnings("unchecked")
	public static void clean(final Object buffer) throws Exception {
		AccessController.doPrivileged(new PrivilegedAction() {
			public Object run() { 
				try {
					Method getCleanerMethod = buffer.getClass().getMethod("cleaner",new Class[0]);
					getCleanerMethod.setAccessible(true);
					sun.misc.Cleaner cleaner =(Cleaner)getCleanerMethod.invoke(buffer,new Object[0]);
					cleaner.clean();
				} catch(Exception e) {
					e.printStackTrace();
				}
				return null;}});

	}
	/*
	 * 读取文件到byte数组
	 */
	@SuppressWarnings("resource")
	public static byte[] readFiletoNByteArray(String filename, long start, long size)throws IOException{  
		//System.out.println("READ MAP: "+start + "---------> " + size); 
		FileChannel fc = null;  
		MappedByteBuffer byteBuffer = null;
		try{  
			fc = new RandomAccessFile(filename,"r").getChannel();  
			byteBuffer = fc.map(MapMode.READ_ONLY, start, size).load();  
			byte[] result = new byte[(int) size];  
			if (byteBuffer.remaining() > 0) {  
				byteBuffer.get(result, 0, byteBuffer.remaining());  
			} 
			fc.close();  
			/*
			try {
				Method  m = FileChannelImpl.class.getDeclaredMethod("unmap", MappedByteBuffer.class);
				m.setAccessible(true);  
				try {
					m.invoke(FileChannelImpl.class, byteBuffer);
				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
					e1.printStackTrace();
				}
			} catch (NoSuchMethodException | SecurityException e1) {
				e1.printStackTrace();
			}
			 */
			try {
				clean(byteBuffer);
				fc.close();  
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return result; 
		}catch (IOException e) {  
			if(fc!=null )fc.close();  
			if(byteBuffer!=null)
				try {
					clean(byteBuffer);
				} catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			//e.printStackTrace();  
			System.out.println("发现异常文件并删除，文件名为: "+filename ); 
			deleteFile(filename);
			return null;
			//throw e;  
		}
	} 
	/**
	 * 读取文件到byte数组
	 * @param filename
	 * @return
	 * @throws IOException
	 */
	@SuppressWarnings("resource")
	public static byte[] readFiletoByteArray(String filename)throws IOException{  
		FileChannel fc = null;  
		try{  
			fc = new RandomAccessFile(filename,"r").getChannel();  
			MappedByteBuffer byteBuffer = fc.map(MapMode.READ_ONLY, 0, fc.size()).load();  
			System.out.println(byteBuffer.isLoaded());  
			byte[] result = new byte[(int)fc.size()];  
			if (byteBuffer.remaining() > 0) {  
				//	              System.out.println("remain");  
				byteBuffer.get(result, 0, byteBuffer.remaining());  
			}  
			fc.close();  
			try {
				clean(byteBuffer);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return result;  
		}catch (IOException e) {  
			e.printStackTrace();  
			throw e;  
		}finally{  
			try{  
				fc.close();  
			}catch (IOException e) {  
				e.printStackTrace();  
			}  
		}  
	} 

	/**
	 * byte 数组与 int 的相互转换
	 * @param b
	 * @return
	 */
	public static int byteArrayToInt(byte[] b) {
		return   b[3] & 0xFF |
				(b[2] & 0xFF) << 8 |
				(b[1] & 0xFF) << 16 |
				(b[0] & 0xFF) << 24;
	}
	public static byte[] intToByteArray(int a) {
		return new byte[] {
				(byte) ((a >> 24) & 0xFF),
				(byte) ((a >> 16) & 0xFF),   
				(byte) ((a >> 8) & 0xFF),   
				(byte) (a & 0xFF)
		};
	}

	/**
	 * byte 数组与 long 的相互转换
	 * @param x
	 * @return
	 */
	public static byte[] longToBytes(long x) {
		ByteBuffer buffer = ByteBuffer.allocate(8);   
		buffer.putLong(0, x);
		return buffer.array();
	}

	public static long bytesToLong(byte[] bytes) {
		ByteBuffer buffer = ByteBuffer.allocate(8);   
		buffer.put(bytes, 0, bytes.length);
		buffer.flip();//need flip 
		return buffer.getLong();
	}

	/**
	 * 合并两个byte数组
	 * @param data1
	 * @param data2
	 * @return
	 */
	public static byte[] addBytes(byte[] data1, byte[] data2) {
		byte[] data3 = new byte[data1.length + data2.length];
		System.arraycopy(data1, 0, data3, 0, data1.length);
		System.arraycopy(data2, 0, data3, data1.length, data2.length);
		return data3;
	}

	/**
	 * 将字节数组写入文件
	 * @param bytes
	 * @param to
	 * @return
	 */
	public static void write(byte[] from, File to) {
		if (from == null) {
			throw new NullPointerException("bytes is null");
		}
		if (to == null) {
			throw new NullPointerException("file is null");
		}
		BufferedOutputStream bos = null;
		try {
			bos = new BufferedOutputStream(new FileOutputStream(to));
			bos.write(from);
			closeQuietly(bos);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeQuietly(bos);
		}
	}

	/**
	 * 小文件(不超过1MB)转成字节数组
	 * @param file
	 * @return
	 * @throws IllegalArgumentException
	 *             待转换的文件超过 1MB
	 */
	public static byte[] toBytes(File file) {
		if (file == null || file.exists() == false) {
			return null;
		}

		final long size = 1 * 1024 * 1024;//1M
		final long fileLen = file.length();
		if (fileLen > size) {
			throw new IllegalArgumentException("file length exceeds " + size
					+ " B");
		}

		ByteArrayOutputStream baos = new ByteArrayOutputStream((int) fileLen);

		int len = -1;
		byte[] buf = new byte[4 * 1024];
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(file);
			while (-1 != (len = fis.read(buf))) {
				baos.write(buf, 0, len);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeQuietly(fis);
		}

		return baos.toByteArray();
	}

	/**
	 * 关闭流
	 * 
	 * @param stream
	 */
	public static void closeQuietly(Closeable stream) {
		if (stream != null) {
			try {
				stream.close();
			} catch (IOException e) {
				// ignore
			}
		}
	}

	public static List<String> tree(String path){
		List<String> lstFileNames = new ArrayList<String>();
		File f = new File(path);
		if(!f.exists())return lstFileNames;
		if(!f.isDirectory()){
			return lstFileNames;
		}
		else{
			File[] t = f.listFiles();
			for(int i=0;i<t.length;i++){
				if(!t[i].isDirectory()){
					lstFileNames.add(t[i].getName());
					//System.out.println(t[i].getName());
				}
			}
		}
		return lstFileNames;
	}
	public static boolean contains(String[] stringArray, String source) {
		// 转换为list
		List<String> tempList = Arrays.asList(stringArray);
		// 利用list的包含方法,进行判断
		if(tempList.contains(source))
		{
			return true;
		} else {
			return false;
		}
	}
	//String objectTime = "20160728141602";
	public static String findDataName(String objectTime, String []matherString){
		SimpleDateFormat sdf= new SimpleDateFormat("yyyyMMddHHmmss");
		long fetchTime = 0;
		try {
			if(objectTime == null || objectTime.length() != 14)
				return null;
			fetchTime = sdf.parse(objectTime).getTime();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		//System.out.println(fetchTime);
		if(contains(matherString,objectTime))return objectTime;
		int cnt = 1;
		String timeString = null;
		Date date = new Date(fetchTime);		
		while(true){	
			date.setTime(fetchTime-1000 * cnt);
			timeString = sdf.format(date);
			//System.out.println(timeString);
			if(contains(matherString,timeString))return timeString;

			date.setTime(fetchTime+1000 * cnt);
			timeString = sdf.format(date);
			//System.out.println(timeString);
			if(contains(matherString,timeString))return timeString;

			if(cnt++ > 5)break; 
		}
		return null;
	}

	// 转化字符串为十六进制编码 
	public static String toHexString(String s) 
	{ 
		String str=""; 
		for (int i=0;i<s.length();i++) 
		{ 
			int ch = (int)s.charAt(i); 
			String s4 = Integer.toHexString(ch); 
			str = str + s4; 
		} 
		return str; 
	} 

	// 转化十六进制编码为字符串 
	public static String toStringHex(String s) 
	{ 
		byte[] baKeyword = new byte[s.length()/2]; 
		for(int i = 0; i < baKeyword.length; i++) 
		{ 
			try 
			{ 
				baKeyword[i] = (byte)(0xff & Integer.parseInt(s.substring(i*2, i*2+2),16)); 
			} 
			catch(Exception e) 
			{ 
				e.printStackTrace(); 
			} 
		} 
		try 
		{ 
			s = new String(baKeyword, "utf-8");//UTF-16le:Not 
		} 
		catch (Exception e1) 
		{ 
			e1.printStackTrace(); 
		} 
		return s; 
	} 
	public static void main(String[] args) { 
		System.out.println(encode("中文")); 
		System.out.println(decode(encode("中文"))); 
	} 
	/* 
	 * 16进制数字字符集 
	 */ 
	private static String hexString="0123456789ABCDEF"; 
	/* 
	 * 将字符串编码成16进制数字,适用于所有字符（包括中文） 
	 */ 
	public static String encode(String str) 
	{ 
		//根据默认编码获取字节数组 
		byte[] bytes=str.getBytes(); 
		StringBuilder sb=new StringBuilder(bytes.length*2); 
		//将字节数组中每个字节拆解成2位16进制整数 
		for(int i=0;i<bytes.length;i++) 
		{ 
			sb.append(hexString.charAt((bytes[i]&0xf0)>>4)); 
			sb.append(hexString.charAt((bytes[i]&0x0f)>>0)); 
		} 
		return sb.toString(); 
	} 
	/* 
	 * 将16进制数字解码成字符串,适用于所有字符（包括中文） 
	 */ 
	public static String decode(String bytes) 
	{ 
		ByteArrayOutputStream baos=new ByteArrayOutputStream(bytes.length()/2); 
		//将每2位16进制整数组装成一个字节 
		for(int i=0;i<bytes.length();i+=2) 
			baos.write((hexString.indexOf(bytes.charAt(i))<<4 |hexString.indexOf(bytes.charAt(i+1)))); 
		return new String(baos.toByteArray()); 
	} 
	/** 
	 * 复制单个文件 
	 * @param oldPath String 原文件路径 如：c:/fqf.txt 
	 * @param newPath String 复制后路径 如：f:/fqf.txt 
	 * @return boolean 
	 */ 
	public static void copyFile(String oldPath, String newPath) { 
		try { 
			int bytesum = 0; 
			int byteread = 0; 
			File oldfile = new File(oldPath); 
			if (oldfile.exists()) {                  //文件存在时 
				InputStream inStream = new FileInputStream(oldPath);      //读入原文件 
				FileOutputStream fs = new FileOutputStream(newPath); 
				byte[] buffer = new byte[1024]; 
				while ( (byteread = inStream.read(buffer)) != -1) { 
					bytesum += byteread;            //字节数 文件大小 
					//System.out.println(bytesum); 
					fs.write(buffer, 0, byteread); 
				} 
				fs.flush();
				inStream.close(); 
				fs.close();
			} 
		}  catch (Exception e) { 
			System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~复制单个文件操作出错"); 
			e.printStackTrace(); 
		} 
	} 

	/** 
	 * 复制整个文件夹内容 
	 * @param oldPath String 原文件路径 如：c:/fqf 
	 * @param newPath String 复制后路径 如：f:/fqf/ff 
	 * @return boolean 
	 */ 
	public static void copyFolder(String oldPath, String newPath) { 


		try { 
			(new File(newPath)).mkdirs();       //如果文件夹不存在 则建立新文件夹 
			File a=new File(oldPath); 
			String[] file=a.list(); 
			File temp=null; 
			for (int i = 0; i < file.length; i++) { 
				if(oldPath.endsWith(File.separator)){ 
					temp=new File(oldPath+file[i]); 
				} 
				else{ 
					temp=new File(oldPath+File.separator+file[i]); 
				} 


				if(temp.isFile()){ 
					FileInputStream input = new FileInputStream(temp); 
					FileOutputStream output = new FileOutputStream(newPath + "/" + (temp.getName()).toString()); 
					byte[] b = new byte[1024 * 5]; 
					int len; 
					while ( (len = input.read(b)) != -1) { 
						output.write(b, 0, len); 
					} 
					output.flush(); 
					output.close(); 
					input.close(); 
				} 
				if(temp.isDirectory()){           //如果是子文件夹 
					copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]); 
				} 
			} 
		}  catch (Exception e) { 
			System.out.println("复制整个文件夹内容操作出错"); 
			e.printStackTrace(); 
		} 
	}
	public static boolean deleteFile(String sPath) {
		
		Boolean flag = false;
		File file = new File(sPath);
		// 路径为文件且不为空则进行删除
		if (file.isFile() && file.exists()) {// System.out.println("开始删除文件1:"+sPath); 
		return file.delete();
		}
		return flag;

	}
	public static boolean deleteFile( File file) {
		Boolean flag = false;
		// 路径为文件且不为空则进行删除
		if (file.isFile() && file.exists()) {//System.out.println("开始删除文件2:"+file.getPath());
		return file.delete();
		}
		return flag;
	}
	public static long dateToLong(String sDt){
		SimpleDateFormat sdf= new SimpleDateFormat("yyyyMMddHHmmss");
		Date dt2 = null;
		try {
			dt2 = sdf.parse(sDt);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//继续转换得到秒数的long型
		long lTime = dt2.getTime()/1000l;
		return lTime;
	}
	
	 public static String TIME_FORMAT = "yyyyMMddHHmmss";

	/**
	  * 将日期格式的字符串转换为长整型
	  * 
	  * @param date
	  * @param format
	  * @return
	  */
	 public static long convert2long(String date) {
	  try {
	    SimpleDateFormat sf = new SimpleDateFormat(TIME_FORMAT);
	    return (sf.parse(date).getTime())/1000l;
	   
	  } catch (ParseException e) {
	   e.printStackTrace();
	  }
	  return 0l;
	 }
	 public static long convert2long2(String date) {
		  try {
		    SimpleDateFormat sf = new SimpleDateFormat(TIME_FORMAT);
		    return (sf.parse(date).getTime());
		   
		  } catch (ParseException e) {
		   e.printStackTrace();
		  }
		  return 0l;
		 }
	 /* 
	     * 将时间转换为时间戳
	     */    
	    public static String dateToStamp(String s) throws ParseException{
	        String res;
	        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(TIME_FORMAT);
	        Date date = simpleDateFormat.parse(s);
	        long ts = date.getTime();
	        res = String.valueOf(ts);
	        return res;
	    }
		public static boolean checkIP(String str) {
			Pattern pattern = Pattern
					.compile("^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]"
							+ "|[*])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]|[*])$");
			return pattern.matcher(str).matches();
		}
}
